package cn.com.doone.common.uc.oauth.authorize;

import static cn.com.doone.common.uc.domain.oauth.Constants.OAUTH_LOGIN_VIEW;
import static cn.com.doone.common.uc.domain.oauth.Constants.REQUEST_USERNAME;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

import cn.com.doone.common.uc.domain.oauth.AccessToken;
import cn.com.doone.common.uc.oauth.OAuthAuthxRequest;
import cn.com.doone.common.uc.oauth.shiro.OAuth2Token;
import cn.com.doone.common.uc.oauth.validator.AbstractClientDetailsValidator;
import cn.com.doone.common.uc.oauth.validator.SMSClientDetailValidator;
import cn.com.doone.common.uc.web.WebUtils;

public class SMSAuthorizeHandler extends AbstractAuthorizeHandler {

	private static final Logger LOG = LoggerFactory.getLogger(WedoAuthorizeHandler.class);
	
	private AccessToken accessToken;

	public SMSAuthorizeHandler(OAuthAuthxRequest oauthRequest,HttpServletResponse response) {
		super(oauthRequest, response);
	}

	@Override
	protected AbstractClientDetailsValidator getValidator() {
		return new SMSClientDetailValidator(oauthRequest, oauthRequest.request());
	}

public void handle() throws Exception {
		
		LOG.debug("######################   登录跳转START   ###########################");
		
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		LOG.debug("验证码身份认证开始时间：" + df.format(new Date()));
		
		if (smsValid()) {
			return;
		}
    	
		LOG.debug("验证码身份认证结束时间：" + df.format(new Date()));
		
    	//valiblackip
    	/*if(valiBlackIP()) {
    		return;
    	}*/
    	
		LOG.debug("请求合法性认证开始时间：" + df.format(new Date()));
		
        // validate
        if (validateFailed()) {
            return;
        }
        
        LOG.debug("请求合法性认证结束时间：" + df.format(new Date()));

        LOG.debug("是否需要登录认证开始时间：" + df.format(new Date()));
        // Check need usr login
//        if (goLogin()) {
//            return;
//        }
        
        LOG.debug("是否需要登录认证开始时间：" + df.format(new Date()));

        // 认证IP锁
        /*if (validIpLock()){
        	return;
        }*/
        
        // 是否需要登陆 
        /*if (isSubmitLogin()) {
        	// 账号锁
            if (validAccountLock()) {
            	return;
            }
        }*/
        
        LOG.debug("登录请求认证开始时间：" + df.format(new Date()));
        
        //submit login
        if (submitLogin()) {
            return;
        }
        
        LOG.debug("登录请求认证结束时间：" + df.format(new Date()));
    	// 验证是否为弱密码
        /*if (isWeakPassword()) {
        	return;
        }*/
        
        LOG.debug("获取账号及应用信息开始时间：" + df.format(new Date()));
        
        // 获取并设置userId和appInfoId
        this.setAttribute();
        
        LOG.debug("获取账号及应用信息结束时间：" + df.format(new Date()));
        
        
        LOG.debug("用户组权限认证开始时间：" + df.format(new Date()));
        // vali authorize
        if(valiAuthorize()) {
        	return;
        }
        LOG.debug("用户组权限认证结束时间：" + df.format(new Date()));

        LOG.debug("用户自身授权认证开始时间：" + df.format(new Date()));
        // Check approval
        if (goApproval()) {
            return;
        }

        // Submit approval
        if (submitApproval()) {
            return;
        }
        LOG.debug("用户自身授权认证结束时间：" + df.format(new Date()));

        //handle response
        handleResponse();
    }
	
	@SuppressWarnings("unused")
	private boolean smsValid() throws Exception {
		
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		HttpServletRequest request = oauthRequest.request();
		
		String client_id = request.getParameter("client_id");
    	String scope = request.getParameter("scope");
    	String response_type = request.getParameter("response_type");
    	String redirect_uri = request.getParameter("redirect_uri");
    	String state = request.getParameter("state");
    	String client_secret = request.getParameter("client_secret");
    	String userAccount = request.getParameter("userAccount");
    	String mobilePhone = request.getParameter("mobilePhone");
    	String smsCode = request.getParameter("smsCode");
    	String url = request.getParameter("url");
    	LOG.debug("------------------>clientId:" + client_id);
    	LOG.debug("------------------>clientSecret:" + client_secret);
    	
    	Map<String, Object> map = new HashMap<String, Object>();
    	map.put("userAccount", userAccount);
    	map.put("mobilePhone", mobilePhone);
    	map.put("code", smsCode);
    	List<Map<String, Object>> list = phoneService.searchUserByAccountAndPhone(map);
    	if (list.size() > 0) {
    		request.setAttribute(REQUEST_USERNAME, list.get(0).get("userAccount"));
    		request.setAttribute("USER_INFO_ID", list.get(0).get("userInfoId"));
    		
        	
    	} else {
    		url += "&flag=error";
    		final OAuthResponse oAuthResponse = OAuthASResponse
    				.authorizationResponse(oauthRequest.request(), HttpServletResponse.SC_FOUND)
                    .location(url)
                    .buildQueryMessage();
            
            WebUtils.writeOAuthQueryResponse(response, oAuthResponse);
            return true;
    	}
    	
    	
    	LOG.debug("根据OA账号获取ACCESS_TOKEN开始时间：" + df.format(new Date()));
    	accessToken = oauthService.loadAccessToken(client_id, (String) request.getAttribute(REQUEST_USERNAME), null);
    	LOG.debug("根据OA账号获取ACCESS_TOKEN结束时间：" + df.format(new Date()));
    	System.out.println("------------->accessToken" + JSON.toJSONString(accessToken));
    	
    	LOG.debug("ACCESS_TOKEN合法性认证开始时间：" + df.format(new Date()));
    	if (accessToken != null) {
    		if (accessToken.tokenExpired()) {	// AccessToken已过期
    			if (accessToken.refreshTokenExpired()) {	// 刷新令牌已过期
    				accessToken = oauthService.retrieveNewAccessTokenByUsername(clientDetails(), (String) request.getAttribute(REQUEST_USERNAME));
    			} else {									// 刷新令牌已过期
    				accessToken = oauthService.changeAccessTokenByRefreshToken(accessToken.refreshToken(), accessToken.clientId());
    			}
    		}
    	} else {
    		accessToken = oauthService.retrieveNewAccessTokenByUsername(clientDetails(), (String) request.getAttribute(REQUEST_USERNAME));
    	}
    	LOG.debug("ACCESS_TOKEN合法性认证结束时间：" + df.format(new Date()));
		return false;
	}
	
	
	@Override
	protected boolean submitLogin() throws  ServletException, IOException {
		if (isSubmitLogin()) {
            //login flow
            try {
            	final HttpServletRequest request = oauthRequest.request();
            	
            	System.out.println("------------------------->" + request.getAttribute(REQUEST_USERNAME));
            	
            	AuthenticationToken token = new OAuth2Token(accessToken.tokenId(), "os-resource").setUserId((String) request.getAttribute(REQUEST_USERNAME));
            	
                SecurityUtils.getSubject().login(token);
                
                // 保存登录日志
                this.logLogin((String) request.getAttribute(REQUEST_USERNAME), "1");
                
                // 更新账号锁定状态
                Map<String, Object> userMap = new HashMap<String, Object>();
                int userInfoId = this.oauthService.findUserInfoIdByAccount((String) request.getAttribute(REQUEST_USERNAME));
    			userMap.put("userInfoId", userInfoId);
    			userMap.put("lockLevel", "0");
    			userMap.put("invalidTime", null);
    			
    			this.oauthService.updateUserLock(userMap);

                LOG.debug("Submit login successful");
         
                this.userFirstLogged = true;
                return false;
            } catch (Exception ex) {
            	
            	ex.printStackTrace();
                //login failed
                LOG.debug("Login failed, back to login page too", ex);
                final HttpServletRequest request = oauthRequest.request();
                
                // 保存登录日志
                this.logLogin((String) request.getAttribute(REQUEST_USERNAME), "0");

                request.setAttribute("username", request.getAttribute(REQUEST_USERNAME));
                request.setAttribute("oauth_login_error", true);
                request.setAttribute("oauth_login_error_message", "用户名或密码错误！！");
                request.getRequestDispatcher(OAUTH_LOGIN_VIEW).forward(request, response);
                return true;
            }
        }
        return false;
	}
	
	protected void responseApprovalDeny() throws IOException, OAuthSystemException {

		String redirectUri = (String) oauthRequest.request().getAttribute("redirect_uri");
		
        final OAuthResponse oAuthResponse = OAuthASResponse.errorResponse(HttpServletResponse.SC_FOUND)
                .setError(OAuthError.CodeResponse.ACCESS_DENIED)
                .setErrorDescription("User denied access")
                .location(redirectUri)
                .setState(oauthRequest.getState())
                .buildQueryMessage();
        LOG.debug("'ACCESS_DENIED' response: {}");

        WebUtils.writeOAuthQueryResponse(response, oAuthResponse);

        //user logout when deny
        final Subject subject = SecurityUtils.getSubject();
        subject.logout();
        LOG.debug("After 'ACCESS_DENIED' call logout. user: {}");
    }
	
	@Override
	protected void handleResponse() throws OAuthSystemException, IOException {
		String redirectUri = (String) oauthRequest.request().getParameter("redirect_uri");
		
		final OAuthResponse oAuthResponse = OAuthASResponse.authorizationResponse(oauthRequest.request(), HttpServletResponse.SC_FOUND)
                .location(redirectUri)
                .buildQueryMessage();
		
        WebUtils.writeOAuthQueryResponse(response, oAuthResponse);
		
	}

}
